package com.atguigu.juc.cas;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @Description: ABA问题演示和解决方案 （加一个版本号）
 * @author： yeswater
 * @create： 2024/5/30
 */

public class ABADemo {
	static AtomicInteger atomicInteger = new AtomicInteger(100); // 可能出现aba问题
	static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);
	
	public static void main(String[] args) {
//        abaHappen();//true	2023
		/**
		 * t3	首次版本号: 1
		 * t4	首次版本号: 1
		 * t3	2次版本号: 2
		 * t3	3次版本号: 3
		 * false	100	3
		 */
		abaNoHappen();
		
	}
	
	private static void abaNoHappen() {
		new Thread(() -> {
			int stamp = atomicStampedReference.getStamp();
			System.out.println(Thread.currentThread().getName() + "\t" + "首次版本号: " + stamp);
			try {
				TimeUnit.MILLISECONDS.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
			System.out.println(Thread.currentThread().getName() + "\t" + "2次版本号: " + atomicStampedReference.getStamp());
			atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
			//atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() - 1); // 实践中这里版本号应该自定义封装 不提供 -1
			System.out.println(Thread.currentThread().getName() + "\t" + "3次版本号: " + atomicStampedReference.getStamp());
		}, "t3").start();
		
		
		new Thread(() -> {
			int stamp = atomicStampedReference.getStamp();
			System.out.println(Thread.currentThread().getName() + "\t" + "首次版本号: " + stamp);
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			boolean b = atomicStampedReference.compareAndSet(100, 200, stamp, stamp + 1);
			System.out.println(b + "\t" + atomicStampedReference.getReference() + "\t" + atomicStampedReference.getStamp());
		}, "t4").start();
	}
	
	private static void abaHappen() {
		new Thread(() -> {
			atomicInteger.compareAndSet(100, 101);
			try {
				TimeUnit.MILLISECONDS.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			atomicInteger.compareAndSet(101, 100);
		}, "t1").start();
		
		
		new Thread(() -> {
			try {
				TimeUnit.MILLISECONDS.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(atomicInteger.compareAndSet(100, 2023) + "\t" + atomicInteger.get());//true	2023
		}, "t2").start();
	}
}
